﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Security.Cryptography;
using Ionic.Zip;

namespace folderPatch
{
    public partial class frmPatch : Form
    {
        public frmPatch()
        {
            InitializeComponent();
        }

        private void btnBase_Click(object sender, EventArgs e)
        {
            DialogResult result = dlgBase.ShowDialog();
            if (result == DialogResult.OK)
            {
                txtBase.Text = dlgBase.SelectedPath;
            }
        }

        private void btnTarget_Click(object sender, EventArgs e)
        {
            DialogResult result = dlgBase.ShowDialog();
            if (result == DialogResult.OK)
            {
                txtTarget.Text = dlgBase.SelectedPath;
            }
        }

        private void btnGeneratePatch_Click(object sender, EventArgs e)
        {
            Dictionary<string, string> baseMd5 = new Dictionary<string, string>();
            foreach (string file in Directory.GetFiles(txtBase.Text, "*", SearchOption.AllDirectories))
            {
                var baseFileName = file.Replace(txtBase.Text, "");
                var baseFileMd5 = getMd5(file);
                baseMd5.Add(baseFileName, baseFileMd5);
                //Console.WriteLine("Processing file :" + baseFileName + baseFileMd5);
            }
            Console.WriteLine("Processing targets............");
            Dictionary<string, string> targetMd5 = new Dictionary<string, string>();
            List<string> patchFiles = new List<string>();
            foreach (string file in Directory.GetFiles(txtTarget.Text, "*", SearchOption.AllDirectories))
            {
                var targetFileName = file.Replace(txtTarget.Text, "");
                var targetFileMd5 = getMd5(file);
                targetMd5.Add(targetFileName, targetFileMd5);
                if (baseMd5.ContainsKey(targetFileName))
                {
                    if (baseMd5[targetFileName] != targetFileMd5)
                    {
                        //we can use a diff here
                        //just coping for now
                        Console.WriteLine("File to be updated" + file);
                        patchFiles.Add(file);
                    }
                    else
                        ;//Console.WriteLine("Files are same");
                }
                else
                {
                    Console.WriteLine("File to be added" + file);
                    patchFiles.Add(file);
                }
                //Console.WriteLine("Processing file :" + targetFileName + targetFileMd5);
            }
            //Creating patch
            using (ZipFile zip = new ZipFile())
            {
                foreach (var file in patchFiles)
                {
                    zip.AddFile(file, file.Replace(txtTarget.Text,"").Replace(Path.GetFileName(file),""));
                }
                zip.Save(txtPatch.Text);
                MessageBox.Show("Patch file created successfully.");
            }
        }   

        private void btnApplyPatch_Click(object sender, EventArgs e)
        {
            string patchToUnpack = txtPatch.Text;
            string unpackDirectory = txtTarget.Text;
            if(String.IsNullOrEmpty(unpackDirectory))
                unpackDirectory = txtBase.Text;
            using (ZipFile zip = ZipFile.Read(patchToUnpack))
            {
                // here, we extract every entry, but we could extract conditionally
                // based on entry name, size, date, checkbox status, etc.  
                foreach (ZipEntry zipEntry in zip)
                {
                    zipEntry.Extract(unpackDirectory, ExtractExistingFileAction.OverwriteSilently);
                }
                MessageBox.Show("Patch applied successfully");
            }
        }

        private string getMd5(string filePath)
        {
            FileStream fileStream = new FileStream(filePath, FileMode.Open);
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] retVal = md5.ComputeHash(fileStream);
            fileStream.Close();

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < retVal.Length; i++)
            {
                sb.Append(retVal[i].ToString("x2"));
            }
            return sb.ToString();
        }

        private void btnPatch_Click(object sender, EventArgs e)
        {
            DialogResult result = dlgPatch.ShowDialog();
            if (result == DialogResult.OK)
            {
                txtPatch.Text = dlgPatch.FileName;
            }
        }
    }
}
